package com.usian.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.usian.common.wemedia.WemediaContants;
import com.usian.model.admin.dtos.NewsAuthDto;
import com.usian.model.common.constants.NewsAutoScanConstants;
import com.usian.model.common.dtos.PageResponseResult;
import com.usian.model.common.dtos.ResponseResult;
import com.usian.model.common.enums.AppHttpCodeEnum;
import com.usian.model.media.dtos.WmNewsDto;
import com.usian.model.media.dtos.WmNewsPageReqDto;
import com.usian.model.media.pojos.WmMaterial;
import com.usian.model.media.pojos.WmNews;
import com.usian.model.media.pojos.WmNewsMaterial;
import com.usian.model.media.pojos.WmUser;
import com.usian.model.media.vo.WmNewsVO;
import com.usian.utils.threadlocal.WmThreadLocalUtils;
import com.usian.wemedia.mapper.WmMaterialMapper;
import com.usian.wemedia.mapper.WmNewsMapper;
import com.usian.wemedia.mapper.WmNewsMaterialMapper;
import com.usian.wemedia.mapper.WmUserMapper;
import com.usian.wemedia.service.WmNewsService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Transactional
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews>
        implements WmNewsService {

    @Value("${fastdfs.url}")
    private String fastServiceUrl;

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private KafkaTemplate kafkaTemplate;

    @Override
    public ResponseResult findList(WmNewsPageReqDto dto) {
        // 1.参数校验
        dto.checkParam();
        LambdaQueryWrapper<WmNews> wmNewsWrapper = Wrappers.<WmNews>lambdaQuery();
        // 2.构建条件--status查询
        if (null != dto.getStatus()) {
            wmNewsWrapper.eq(WmNews::getStatus, dto.getStatus());
        }
        // 3.构建条件--title模糊查询
        if (null != dto.getKeyword()) {
            wmNewsWrapper.like(WmNews::getTitle, dto.getKeyword());
        }
        // 4.构建条件--channel_id查询
        if (null != dto.getChannelId()) {
            wmNewsWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }
        // 5.构建条件--发布日期查询
        if (null != dto.getBeginPubDate() && null != dto.getEndPubDate()) {
            wmNewsWrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
        }
        // 6.构建条件--当前用户查询
        WmUser user = WmThreadLocalUtils.getUser();
        if (null == user) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        wmNewsWrapper.eq(WmNews::getUserId, user.getId());
        // 7.排序--created_time倒序排列
        wmNewsWrapper.orderByDesc(WmNews::getCreatedTime);
        // 8.调用api分页查询
        Page<WmNews> pageParam = new Page<>(dto.getPage(), dto.getSize());
        IPage<WmNews> pageResult = page(pageParam, wmNewsWrapper);
        PageResponseResult pageResponseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) pageResult.getTotal());
        pageResponseResult.setData(pageResult.getRecords());
        pageResponseResult.setHost(fastServiceUrl);
        // 9.进行返回
        return pageResponseResult;
    }

    @Override
    public ResponseResult submitNews(WmNewsDto dto, short code) {
        // 1.参数校验
        if (null == dto || StringUtils.isEmpty(dto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        // 2.设置wmnews相关的参数 user_id type created_time submited_time  images enable
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto, wmNews);
        WmUser user = WmThreadLocalUtils.getUser();
        if (null == user) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        wmNews.setUserId(user.getId());
        if (wmNews.getType().shortValue() == WemediaContants.WM_NEWS_TYPE_AUTO.shortValue()) {
            wmNews.setType(null);
        }
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short)1);
        // 先判断images是否有值
        if (null != dto.getImages() && !dto.getImages().isEmpty()) {
            // [1, 2]
            wmNews.setImages(dto.getImages().toString()
                    .replace("[", "")
                    .replace("]", "")
                    .replace(fastServiceUrl, "")
                    .replace(" ", ""));
        }
        // 3.修改或者是新增保存
        // 是新增还是修改
        boolean flag = false;
        if (dto.getId() == null) {
            // 新增
            flag = save(wmNews);
        } else {
            // 修改
            flag = updateById(wmNews);
            LambdaUpdateWrapper<WmNewsMaterial> wmMaterialWrapper =
                    Wrappers.<WmNewsMaterial>lambdaUpdate().eq(WmNewsMaterial::getNewsId, wmNews.getId());
            wmNewsMaterialMapper.delete(wmMaterialWrapper);
        }
        if (flag) {
            // 发送kafka消息
            kafkaTemplate.send(NewsAutoScanConstants.WM_NEWS_AUTO_SCAN_TOPIC, wmNews.getId());
        }
        if (WmNews.Status.NORMAL.getCode() == dto.getStatus().shortValue()) {
            // 草稿
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        // 4.关联内容和素材的关系
        // 提取图片
        List<Map> contentMapsList = JSON.parseArray(dto.getContent(), Map.class);
        List<String> materials = new ArrayList<>();
        for(Map map : contentMapsList) {
            String type = (String)map.get(WemediaContants.WM_NEWS_TYPE);
            if (type.equals(WemediaContants.WM_NEWS_TYPE_IMAGE)) {
                String imgUrl = (String)map.get(WemediaContants.WM_NEWS_TYPE_VALUE);
                materials.add(imgUrl.replace(fastServiceUrl, ""));
            }
        }
        if (!materials.isEmpty()) {
            ResponseResult responseResult = saveRelation(materials, wmNews.getId(), WemediaContants.WM_CONTENT_REFERENCE);
            if (null != responseResult) {
                return responseResult;
            }
        }
        // 5.关联封面和素材的关系
        List<String> imageList = dto.getImages();
        if (dto.getType().shortValue() == WemediaContants.WM_NEWS_TYPE_AUTO.shortValue()) {
            //
            if (materials.size() >0 && materials.size() <= 2) {
                // 单图
                wmNews.setType(WemediaContants.WM_NEWS_SINGLE_IMAGE);
                imageList = materials.stream().limit(1).collect(Collectors.toList());
            } else if (materials.size() >= 3) {
                // 多图
                wmNews.setType(WemediaContants.WM_NEWS_MANY_IMAGE);
                imageList = materials.stream().limit(3).collect(Collectors.toList());
            } else {
                // 无图
                wmNews.setType(WemediaContants.WM_NEWS_NONE_IMAGE);
            }
            wmNews.setImages(imageList.toString()
                    .replace("[", "")
                    .replace("]", "")
                    .replace(fastServiceUrl, "")
                    .replace(" ", ""));
            updateById(wmNews);
        }
        if (imageList != null && imageList.size() > 0) {
            imageList = imageList.stream().map(item -> {
                return item.replace(fastServiceUrl, "");
            }).collect(Collectors.toList());
            ResponseResult responseResult = saveRelation(imageList, wmNews.getId(), WemediaContants.WM_COVER_REFERENCE);
            if (responseResult != null) {
                return responseResult;
            }
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult queryNewsById(Integer id) {
        // 1.参数校验
        if (null == id) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        // 2.调用api查询news数据
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 3.响应数据
        ResponseResult<WmNews> responseResult = new ResponseResult<>();
        responseResult.ok(wmNews);
        responseResult.setHost(fastServiceUrl);
        return responseResult;
    }

    @Override
    public ResponseResult delNews(Integer id) {
        // 1.参数校验
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        // 2.调用api查询文章详情
        WmNews wmNews = getById(id);
        if (null == wmNews) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 3.做业务规则校验，文章状态为9(已发布)且已上架则不能删除文章
        if (wmNews.getStatus().shortValue() == WmNews.Status.PUBLISHED.getCode()
                && wmNews.getEnable().shortValue() == WemediaContants.WM_NEWS_ENABLE.shortValue()) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DELETE_FAIL,
                    "文章已发布且已上架不能删除！");
        }
        // 4.调用api删除wm_news的数据
        boolean delNewsResult = removeById(id);
        if (!delNewsResult) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DELETE_FAIL, "删除文章失败,服务器内部异常");
        }
        // 5.删除wm_news_material的相关数据

        wmNewsMaterialMapper.delete(Wrappers.
                <WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, id));

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public ResponseResult downOrUpNews(WmNewsDto dto) {
        // 1.参数校验
        if (null == dto || dto.getId() == null || dto.getEnable() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        WmNews wmNews = getById(dto.getId());
        if (null == wmNews) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        // 2.当前已经发布（状态为9）的文章可以上架（enable = 1），也可以下架（enable = 0）
        if (WmNews.Status.PUBLISHED.getCode() != wmNews.getStatus().shortValue()) {
            return ResponseResult.errorResult(AppHttpCodeEnum.UPDATE_FAIL, "文章不是已发布状态,不能上下架！");
        }
        // 3.更新上下架状态
        if (dto.getEnable().shortValue() != WemediaContants.WM_NEWS_NO_ENABLE.shortValue()
                && dto.getEnable().shortValue() != WemediaContants.WM_NEWS_ENABLE.shortValue()) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        boolean updateResult =
                update(Wrappers.<WmNews>lambdaUpdate()
                        .set(WmNews::getEnable, dto.getEnable())
                        .eq(WmNews::getId, dto.getId()));
        if (!updateResult) {
            return ResponseResult.errorResult(AppHttpCodeEnum.UPDATE_FAIL);
        }
        // 发送kafka消息给文章微服务
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    @Override
    public List<WmNews> findRelease() {
        // 查询状态为8并且发布时间小于等于当前时间的 wm_news
        LambdaQueryWrapper<WmNews> wmNewsWrapper =
                Wrappers.<WmNews>lambdaQuery().eq(WmNews::getStatus, WmNews.Status.SUCCESS.getCode()).le(WmNews::getPublishTime, new Date());
        List<WmNews> wmNewsList = list(wmNewsWrapper);
        return wmNewsList;
    }

    @Override
    public ResponseResult findListAndPage(NewsAuthDto newsAuthDto) {
        if (newsAuthDto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        newsAuthDto.checkParam();
        Integer page = newsAuthDto.getPage();
        Integer size = newsAuthDto.getSize();
        newsAuthDto.setPage((page - 1) * size);
        // 调用api查询wmnews相关信息的列表，分页
        // 两表联查   连接查询(内连接、左连接、右连接、全连接)
        List<WmNewsVO> wmNewsVOList = wmNewsMapper.findListAndPage(newsAuthDto);
        Integer total = wmNewsMapper.findListAndPageCount(newsAuthDto);
        ResponseResult responseResult = new PageResponseResult(page, newsAuthDto.getSize(), total);
        responseResult.setData(wmNewsVOList);
        return responseResult;
    }

    @Autowired
    private WmUserMapper wmUserMapper;
    @Override
    public ResponseResult findOne(Integer id) {
        if (id == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        WmNews wmNews = getById(id);
        if (wmNews == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        WmNewsVO wmNewsVO = new WmNewsVO();
        BeanUtils.copyProperties(wmNews, wmNewsVO);
        if (wmUser != null) {
            wmNewsVO.setAuthorName(wmUser.getName());
        }
        return ResponseResult.okResult(wmNewsVO);
    }


    public ResponseResult saveRelation(List<String> imageList, Integer newsId, Short type){
        LambdaQueryWrapper<WmMaterial> wmMaterialLambdaQueryWrapper = Wrappers.<WmMaterial>lambdaQuery();
        wmMaterialLambdaQueryWrapper.in(WmMaterial::getUrl, imageList);
        wmMaterialLambdaQueryWrapper.eq(WmMaterial::getUserId, WmThreadLocalUtils.getUser().getId());
        List<WmMaterial> wmMaterialList = wmMaterialMapper.selectList(wmMaterialLambdaQueryWrapper);
        // 为了防止引用的图片被删除的，再次做验证
        Map<String, Integer> wmMaterialMap =
                wmMaterialList.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
        List<Integer> materialIds = new ArrayList<>();

        for (String url : imageList) {
            if (wmMaterialMap.get(url) == null) {
                return ResponseResult.errorResult(500, "应用图片无效！");
            } else {
                materialIds.add(wmMaterialMap.get(url));
            }
        }
        // material_id  news_id type
        wmNewsMaterialMapper.saveRelations(materialIds, newsId, type);
        return null;
    }

}
